//
//  PushAndPopNavigationController.swift
//  TransitionDemo
//
//  Created by youai on 2019/5/23.
//  Copyright © 2019年 youi. All rights reserved.
//

import Foundation
import UIKit

class PushAndPopNavigationController : UINavigationController,UINavigationControllerDelegate {
    
    var interactionController: UIPercentDrivenInteractiveTransition?
    let leftPan = UIScreenEdgePanGestureRecognizer()
    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self                // for navigation controller custom transitions
        //侧滑
//        leftPan.addTarget(self, action: #selector(handleSwipeFromLeft(edgePan:)))
//        leftPan.edges = .left
//        view.addGestureRecognizer(leftPan)
    }
    
    @objc func handleSwipeFromLeft(edgePan:UIScreenEdgePanGestureRecognizer){
        switch(edgePan.state){
        case .began:
            if viewControllers.count > 1 {
                interactionController = UIPercentDrivenInteractiveTransition()
                popViewController(animated: true)
            } else {
                return
            }
        case .changed:
            let percent = edgePan.translation(in: edgePan.view!).x / edgePan.view!.bounds.size.width
            interactionController?.update(percent)
        default:
            let percent = edgePan.translation(in: edgePan.view!).x / edgePan.view!.bounds.size.width
            if edgePan.state == .changed || edgePan.state == .ended {
                if percent > 0.4 && edgePan.state != .cancelled {
                    interactionController?.finish()
                } else {
                    interactionController?.cancel()
                }
                interactionController = nil
            }
        }
    }
    
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation == .push {
            return fadePushStyle ? FadeTransitioning(nav: self) : PushTransitioning(nav: self)
        } else if operation == .pop {
            let result = PopTransitioning(completion: popTransitionCompletion)
            popTransitionCompletion = nil
            return result
        }
        return nil
    }
    
    var popTransitionCompletion : EMPTY_CLOSURE? = nil
    
    func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return interactionController
    }
    
    fileprivate var remove2ndAfterPush : Bool = false
    var fadePushStyle : Bool = false
    override func pushViewController(_ viewController: UIViewController) {
        remove2ndAfterPush = false
        fadePushStyle = false
        super.pushViewController(viewController, animated: true)
    }
    func switchViewController(_ viewController: UIViewController,fadePushStyle : Bool = false){
        remove2ndAfterPush = true
        self.fadePushStyle = fadePushStyle
        super.pushViewController(viewController, animated: true)
    }
    fileprivate func checkRemove2ndVC(){
        guard remove2ndAfterPush else { return }
        var vcs = viewControllers
        vcs.remove(at: vcs.count-2)
        self.viewControllers = vcs
        remove2ndAfterPush = false
        fadePushStyle = false
    }
}

class FadeTransitioning : NSObject, UIViewControllerAnimatedTransitioning {
    weak var nav:PushAndPopNavigationController? = nil
    let duration:TimeInterval
    
    init(nav:PushAndPopNavigationController,duration:TimeInterval = 0.3){
        self.duration = duration
        self.nav = nav
        super.init()
    }

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        if let toVC = transitionContext.viewController(forKey: .to),
            let fromVC = transitionContext.viewController(forKey: .from) {
            toVC.view.alpha = 0.0
            transitionContext.containerView.addSubview(toVC.view)
            UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
                fromVC.view.alpha = 0.0
                toVC.view.alpha = 1.0
            }) { (_) in
                transitionContext.completeTransition(true)
                self.nav?.checkRemove2ndVC()
            }
        }else{
            transitionContext.completeTransition(true)
            self.nav?.checkRemove2ndVC()
        }
    }
}

class PushTransitioning : NSObject, UIViewControllerAnimatedTransitioning {
    weak var nav:PushAndPopNavigationController? = nil
    let duration:TimeInterval
    init(nav:PushAndPopNavigationController,duration:TimeInterval = 0.3){
        self.duration = duration
        self.nav = nav
        super.init()
    }
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        if let toVC = transitionContext.viewController(forKey: .to),
            let fromVC = transitionContext.viewController(forKey: .from) {
            let finalFrameForVC = transitionContext.finalFrame(for: toVC)
            toVC.view.frame = finalFrameForVC.offsetBy(dx: UIScreen.main.bounds.width, dy: 0)
            transitionContext.containerView.addSubview(toVC.view)
            UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
                fromVC.view.alpha = 0.5
                toVC.view.frame = finalFrameForVC
                fromVC.view.frame = fromVC.view.frame.offsetBy(dx: -50, dy: 0)
            }) { (_) in
                transitionContext.completeTransition(true)
                self.nav?.checkRemove2ndVC()
            }
        }else{
            transitionContext.completeTransition(true)
            self.nav?.checkRemove2ndVC()
        }
    }
}

class PopTransitioning : NSObject, UIViewControllerAnimatedTransitioning {
    let duration:TimeInterval
    let completion:EMPTY_CLOSURE?
    init(completion:EMPTY_CLOSURE? = nil,duration:TimeInterval = 0.3){
        self.duration = duration
        self.completion = completion
        super.init()
    }
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        if let toVC = transitionContext.viewController(forKey: .to),
            let fromVC = transitionContext.viewController(forKey: .from) {
            
            let initFrame = transitionContext.initialFrame(for: fromVC)
            let container = transitionContext.containerView
            let toFinalFrame = transitionContext.finalFrame(for:toVC)
            toVC.view.frame = toFinalFrame.offsetBy(dx: -50, dy: 0)
            container.insertSubview(toVC.view, belowSubview: fromVC.view)
            
            container.sendSubviewToBack(toVC.view)
            let finalFrame = initFrame.offsetBy(dx: SCREEN_WIDTH, dy: 0)
            UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: .curveLinear, animations:{
                fromVC.view.frame = finalFrame
                toVC.view.alpha = 1.0
                toVC.view.frame = toFinalFrame
            }) { (_) in
                let complate = transitionContext.transitionWasCancelled
                transitionContext.completeTransition(!complate)
                self.completion?()
            }
        }else{
            transitionContext.completeTransition(true)
        }
    }
}
